#include "kernel/types.h"
#include "kernel/fcntl.h"
#include "user/user.h"

//#define __DEBUG__

int close_debug(int fd){
#ifdef __DEBUG__
  printf("close fd:[%d] from process:[%d]\n", fd, getpid());
#endif
  int ret = close(fd);
  if(ret != 0){
    fprintf(2, "close fd:%d failed\n", fd);
  }
  return ret;
}


#define READ 0
#define WRITE 1

#define DO_IF_COND(cond, op, format, ...) \
  do { \
    if((cond)){ \
      fprintf(2, format, ##__VA_ARGS__); \
      (op); \
    } \
  } while(0);
 
#define IS_CHILD(pid)    ((pid) == 0)
#define IS_PARENT(pid)  ((pid) > 0)

void primes_print(int pipefd){
  short my_id;
  int ret = 0;
  while( (ret = read(pipefd, (void*)&my_id, 2)) == 2) {
    printf("primes %d\n", (int)my_id);
  }
  close_debug(pipefd);
}


int primes(int pipefd){
  short my_id = 0;
  int ret = read(pipefd, (void*)&my_id, 2);
  if(ret == 0){
    close_debug(pipefd);
    exit(0);
  }
  DO_IF_COND(ret < 1, {exit(-1);}, "process:[%d]read first letter error, ret:%d\n", getpid(), ret)
  printf("prime %d\n", (int)my_id);


  int p[2];
  ret = pipe(p);
  DO_IF_COND(ret == -1, {exit(-1);}, "process:[%d] create pipe failed, ret:[%d]\n", getpid(), ret);

  int pid = fork();
  if(IS_CHILD(pid)){
    close_debug(pipefd);
    close_debug(p[WRITE]);

    return primes(p[READ]);
  }
  else if(IS_PARENT(pid)){
    close_debug(p[READ]);

    short number = 0;
    while( (ret = read(pipefd, &number, 2))  == 2){
      if( number % my_id != 0){
        ret = write(p[WRITE], &number, 2);
        DO_IF_COND(ret < 2, {}, "process:[%d] write %d bytes to process:[%d] with number:[%d] failed", getpid(), ret, pid, number)
      }
    }
    close_debug(pipefd);
    close_debug(p[WRITE]);
    wait(&pid);
    return 0;
  }
  else{
    fprintf(2, "process:[%d] for subprocess failed, pid:%d\n", getpid(), pid);
    close_debug(p[READ]);
    close_debug(p[WRITE]);
    close_debug(pipefd);
    exit(-1);
  }
  return -1;
}

int main(int argc, char *argv[]) 
{
  int p[2];
  int ret = pipe(p);
  DO_IF_COND(ret == -1, {exit(-1);}, "main: create pipe failed, ret:[%d]\n", ret);

  
  for(int i = 2; i <= 35; ++i){
    ret = write(p[WRITE], (const void*)&i, 2);
    DO_IF_COND(ret < 2, {close_debug(p[WRITE]); close_debug(p[READ]);exit(-1);},"write [%u] bytes failed; ret:[%d]\n", 1, ret);
  }
  close_debug(p[WRITE]);

  primes(p[READ]);
  return 0;
}

